/*
 * enc.c
 *
 * Created: 6/13/2013 3:00:32 PM
 *  Author: Tim
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>

//for function prototypes
#include "enc.h"

//for access to allocations
#include "../allocations.h"

#include "../dio/dio.h"

//check to see if we need to be concerned with async types.  My guess is that assigning an async type will still achieve our goal here
status_t encCheckPLOC(uint8_t PLOC,uint8_t index)
{
	switch (PLOC)
	{
		case 0x28:
		//check to see pins D1 and D2 are free
		if(daqAlloc.dio[1].alloc == FEATURE_UTILIZED || daqAlloc.dio[2].alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D3 is free
		else if (daqAlloc.dio[3].alloc == FEATURE_UTILIZED && index)						return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
		case 0x29:
		//check to see pins D2 and D3 are free
		if(daqAlloc.dio[2].alloc == FEATURE_UTILIZED || daqAlloc.dio[3].alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D4 is free
		else if (daqAlloc.dio[4].alloc == FEATURE_UTILIZED && index)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
		case 0x2A:
		//check to see pins D3 and D4 are free
		if(daqAlloc.dio[3].alloc == FEATURE_UTILIZED || daqAlloc.dio[4].alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D5 is free
		else if (daqAlloc.dio[5].alloc == FEATURE_UTILIZED && index)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
		case 0x2B:
		//check to see pins D4 and D5 are free
		if(daqAlloc.dio[4].alloc == FEATURE_UTILIZED || daqAlloc.dio[5].alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D6 is free
		else if (daqAlloc.dio[6].alloc == FEATURE_UTILIZED && index)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
		case 0x2C:
		//check to see pins D5 and D6 are free
		if(daqAlloc.dio[5].alloc == FEATURE_UTILIZED || daqAlloc.dio[6].alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index, return an error.
		//There is no third sequential pin available starting and encoder interface from pin D5
		else if (index)																			return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	
	
	
		case 0x30:
		//check to see pins D12 and D11 are free
		if(daqAlloc.dio[12].alloc == FEATURE_UTILIZED || daqAlloc.dio[11].alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D10 is free
		else if (daqAlloc.dio[10].alloc == FEATURE_UTILIZED && index)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
		case 0x31:
		//check to see pins D11 and D10 are free
		if(daqAlloc.dio[11].alloc == FEATURE_UTILIZED || daqAlloc.dio[10].alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index line check to see if pin D9 is free
		else if (daqAlloc.dio[9].alloc && index)											return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
		case 0x32:
		//check to see pins D10 and D9 are free
		if(daqAlloc.dio[10].alloc == FEATURE_UTILIZED || daqAlloc.dio[9].alloc == FEATURE_UTILIZED)	return OPP_FAILED;
		//If the encoder is supposed to use an Index, return an error.
		//There is no third sequential pin available starting and encoder interface from pin D10
		else if (index)																			return OPP_FAILED;
		else return OPP_SUCCESSFUL;
		break;
	}
	
	return OPP_FAILED;
}
//This function should be called once it has been determined that
//1) The pins for the encoder interface are available
//2) There a timer/counter available for the interface 

void encSetup(uint8_t num,uint8_t PLOC, uint8_t index, uint8_t ABS,uint8_t filterDepth,uint16_t resolution)
{

//This section sets the allocations of the digital pins	
	switch (PLOC)
	{
		case 0x28:
		if (index)
		{
			dioDirClr(1);
			dioSense(PORT_ISC_LEVEL_gc,1);
			dioDirClr(2);
			dioSense(PORT_ISC_LEVEL_gc,2);
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			
			//daqAlloc.dioAlloc0.dio1Alloc	= FEATURE_UTILIZED;
			//daqAlloc.dioAlloc0.dio2Alloc	= FEATURE_UTILIZED;
			//daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
			
			daqAlloc.dio[1].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[1].source = DIO_ENC_CHA;
			
			daqAlloc.dio[2].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[2].source = DIO_ENC_CHB;
			
			daqAlloc.dio[3].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[3].source = DIO_ENC_INDX;
			
		}
		else
		{
			dioDirClr(1);
			dioSense(PORT_ISC_LEVEL_gc,1);
			dioDirClr(2);
			dioSense(PORT_ISC_LEVEL_gc,2);
//			daqAlloc.dioAlloc0.dio1Alloc	= FEATURE_UTILIZED;
//			daqAlloc.dioAlloc0.dio2Alloc	= FEATURE_UTILIZED;
			
			daqAlloc.dio[1].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[1].source = DIO_ENC_CHA;
			
			daqAlloc.dio[2].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[2].source = DIO_ENC_CHB;
		}
		break;
		
		case 0x29:
		if (index)
		{
			dioDirClr(2);
			dioSense(PORT_ISC_LEVEL_gc,2);
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			
		//	daqAlloc.dioAlloc0.dio2Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
		
			daqAlloc.dio[2].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[2].source = DIO_ENC_CHA;
			
			daqAlloc.dio[3].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[3].source = DIO_ENC_CHB;
			
			daqAlloc.dio[4].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[4].source = DIO_ENC_INDX;
		}
		else
		{
			dioDirClr(2);
			dioSense(PORT_ISC_LEVEL_gc,2);
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			
		//	daqAlloc.dioAlloc0.dio2Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
			
			daqAlloc.dio[2].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[2].source = DIO_ENC_CHA;
			
			daqAlloc.dio[3].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[3].source = DIO_ENC_CHB;
			
		}
		break;
		
		case 0x2A:
		if (index)
		{
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			dioDirClr(5);
			dioSense(PORT_ISC_LEVEL_gc,5);
			
			//daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
			//daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
			//daqAlloc.dioAlloc0.dio5Alloc	= FEATURE_UTILIZED;
			
			daqAlloc.dio[3].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[3].source = DIO_ENC_CHA;
			
			daqAlloc.dio[4].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[4].source = DIO_ENC_CHB;
			
			daqAlloc.dio[5].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[5].source = DIO_ENC_INDX;
		}
		else
		{
			dioDirClr(3);
			dioSense(PORT_ISC_LEVEL_gc,3);
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			
		//	daqAlloc.dioAlloc0.dio3Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
			
			daqAlloc.dio[3].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[3].source = DIO_ENC_CHA;
			
			daqAlloc.dio[4].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[4].source = DIO_ENC_CHB;
			
		}
		break;
		
		case 0x2B:
		if (index)
		{
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			dioDirClr(5);
			dioSense(PORT_ISC_LEVEL_gc,5);
			dioDirClr(6);
			dioSense(PORT_ISC_LEVEL_gc,6);
			
		//	daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc0.dio5Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc0.dio6Alloc	= FEATURE_UTILIZED;
		
			daqAlloc.dio[4].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[4].source = DIO_ENC_CHA;
			
			daqAlloc.dio[5].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[5].source = DIO_ENC_CHB;
			
			daqAlloc.dio[6].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[6].source = DIO_ENC_INDX;
		}
		else
		{
			dioDirClr(4);
			dioSense(PORT_ISC_LEVEL_gc,4);
			dioDirClr(5);
			dioSense(PORT_ISC_LEVEL_gc,5);
			
			//daqAlloc.dioAlloc0.dio4Alloc	= FEATURE_UTILIZED;
			//daqAlloc.dioAlloc0.dio5Alloc	= FEATURE_UTILIZED;
			
			daqAlloc.dio[4].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[4].source = DIO_ENC_CHA;
			
			daqAlloc.dio[5].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[5].source = DIO_ENC_CHB;
		}
		break;
		
		case 0x2C:
			dioDirClr(5);
			dioSense(PORT_ISC_LEVEL_gc,5);
			dioDirClr(6);
			dioSense(PORT_ISC_LEVEL_gc,6);
			
		//	daqAlloc.dioAlloc0.dio5Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc0.dio6Alloc	= FEATURE_UTILIZED;
			
			daqAlloc.dio[5].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[5].source = DIO_ENC_CHA;
			
			daqAlloc.dio[6].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[6].source = DIO_ENC_CHB;
			
		break;
		
		
		
		case 0x30:
		if (index)
		{
			dioDirClr(12);
			dioSense(PORT_ISC_LEVEL_gc,12);
			dioDirClr(11);
			dioSense(PORT_ISC_LEVEL_gc,11);
			dioDirClr(10);
			dioSense(PORT_ISC_LEVEL_gc,10);
		//	daqAlloc.dioAlloc1.dio12Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc1.dio11Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc1.dio10Alloc	= FEATURE_UTILIZED;
		
			daqAlloc.dio[12].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[12].source = DIO_ENC_CHA;
			
			daqAlloc.dio[11].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[11].source = DIO_ENC_CHB;
			
			daqAlloc.dio[10].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[10].source = DIO_ENC_INDX;
		}
		else
		{
			dioDirClr(12);
			dioSense(PORT_ISC_LEVEL_gc,12);
			dioDirClr(11);
			dioSense(PORT_ISC_LEVEL_gc,11);
			
			//daqAlloc.dioAlloc1.dio12Alloc	= FEATURE_UTILIZED;
			//daqAlloc.dioAlloc1.dio11Alloc	= FEATURE_UTILIZED;			
			
			daqAlloc.dio[12].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[12].source = DIO_ENC_CHA;
			
			daqAlloc.dio[11].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[11].source = DIO_ENC_CHB;
		}
		break;
		case 0x31:
		if (index)
		{
			dioDirClr(11);
			dioSense(PORT_ISC_LEVEL_gc,11);
			dioDirClr(10);
			dioSense(PORT_ISC_LEVEL_gc,10);
			dioDirClr(9);
			dioSense(PORT_ISC_LEVEL_gc,9);
			
			//daqAlloc.dioAlloc1.dio11Alloc	= FEATURE_UTILIZED;
			//daqAlloc.dioAlloc1.dio10Alloc	= FEATURE_UTILIZED;
			//daqAlloc.dioAlloc1.dio9Alloc	= FEATURE_UTILIZED;

			daqAlloc.dio[11].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[11].source = DIO_ENC_CHA;
			
			daqAlloc.dio[10].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[10].source = DIO_ENC_CHB;
			
			daqAlloc.dio[9].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[9].source = DIO_ENC_INDX;			
		}
		else
		{
			dioDirClr(11);
			dioSense(PORT_ISC_LEVEL_gc,11);
			dioDirClr(10);
			dioSense(PORT_ISC_LEVEL_gc,10);
			
		//	daqAlloc.dioAlloc1.dio11Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc1.dio10Alloc	= FEATURE_UTILIZED;
			
			daqAlloc.dio[11].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[11].source = DIO_ENC_CHA;
			
			daqAlloc.dio[10].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[10].source = DIO_ENC_CHB;
		}
		break;
		case 0x32:
			dioDirClr(10);
			dioSense(PORT_ISC_LEVEL_gc,10);
			dioDirClr(9);
			dioSense(PORT_ISC_LEVEL_gc,9);
			
		//	daqAlloc.dioAlloc1.dio10Alloc	= FEATURE_UTILIZED;
		//	daqAlloc.dioAlloc1.dio9Alloc	= FEATURE_UTILIZED;
			
			daqAlloc.dio[10].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[10].source = DIO_ENC_CHA;
			
			daqAlloc.dio[9].alloc = FEATURE_UTILIZED;
			daqAlloc.dio[9].source = DIO_ENC_CHB;
		break;
	}

	//this section sets up the Event system for QDEC
	
	if	(num)
	{
		//configure the encoder pin location
		EVSYS.CH4MUX = 0x40 | PLOC;
			
		//Encoder 1 enable and parameters
		EVSYS.CH4CTRL =	(index) |										//enable index line if one is specified
		EVSYS_QDEN_bm |													//enable encoder interface
		(filterDepth<<EVSYS_DIGFILT0_bp);								//set the digital filter depth
		
		daqAlloc.encAlloc.enc1Alloc = FEATURE_UTILIZED;
		
		if(index) daqAlloc.encAlloc.enc1Index = FEATURE_UTILIZED;
		
		if(ABS) 
		{
			daqAlloc.encAlloc.enc1Abs = FEATURE_UTILIZED;
			inputSuperPacketLength +=2;
		}
		else
		{
			daqAlloc.encAlloc.enc1Abs = FEATURE_FREE;
			inputSuperPacketLength +=4;	
			TCC1.INTCTRLA = TC_OVFINTLVL_LO_gc;
		}
		//Enable timer for QDEC via channel 2 of the event system
		TCC1.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH4_gc;
		//set the counter depth to 4x the encoder resolution
		TCC1.PER = resolution<<2;
		TCC1.CNT = 0;
		encCount1_32 = 0;
		daqAlloc.timerAlloc.timerC1Alloc = FEATURE_UTILIZED;
		
	}
	else
	{
		//configure the encoder pin location
		EVSYS.CH2MUX = 0x40 | PLOC;
			
		//Encoder 0 enable and parameters
		EVSYS.CH2CTRL =	(index) |										//enable index line if one is specified
		EVSYS_QDEN_bm |													//enable encoder interface
		(filterDepth<<EVSYS_DIGFILT0_bp);								//set the digital filter depth
		
		daqAlloc.encAlloc.enc0Alloc = FEATURE_UTILIZED;
		
		if(index) daqAlloc.encAlloc.enc0Index = FEATURE_UTILIZED;
		
		if(ABS)
		{
			 daqAlloc.encAlloc.enc0Abs = FEATURE_UTILIZED;
			 inputSuperPacketLength +=2;
		}
		else
		{
			daqAlloc.encAlloc.enc0Abs = FEATURE_FREE;
			inputSuperPacketLength +=4;
			TCC0.INTCTRLA = TC_OVFINTLVL_LO_gc;
		}
		
		//Enable timer for QDEC via channel 2 of the event system
		TCC0.CTRLD =	TC_EVACT_QDEC_gc | TC_EVSEL_CH2_gc;
		//set the counter depth to 4x the encoder resolution
		TCC0.PER = resolution<<2;
		TCC0.CNT = 0;
		encCount0_32 = 0;
		daqAlloc.timerAlloc.timerC0Alloc = FEATURE_UTILIZED;
	}
	
	
}

ISR(TCC0_OVF_vect)
{
	//if we are here encoder 0 is incremental type
	if(TCC0.CTRLFSET & TC0_DIR_bm)	encCount0_32 -= TCC0.PER; 
	else							encCount0_32 += TCC0.PER; 
}

ISR(TCC1_OVF_vect)
{
	//if we are here encoder 1 is incremental type
	if(TCC1.CTRLFSET & TC1_DIR_bm)	encCount1_32 -= TCC1.PER;
	else							encCount1_32 += TCC1.PER;
}
